#region "Database"

/*
 * ####     Developer Name : Wang Yucai
 * 
 * ####     Development Tool : Microsoft VisualStudio 2010 Ultimate Edition
 * 
 * ####     Create Time : 2014-07-15 10:07:56
 * 
 * ####     Namespace : Masterduner.SourceStudio.Practices.DevelopmentLibrary.Data.Common
 * 
 * ####     Type Name : Database
 * 
 * ####     Full Name : Masterduner.SourceStudio.Practices.DevelopmentLibrary.Data.Common.Database
 * 
 * ####     Machine Name : GLCHQWYCWINW7
 * 
 * ####     UserName : GUOCOLAND/wangyucai
 * 
 * ####     CLR Version : 4.0.30319.18444
 * 
 * ####     Target Framework Version : 4.0
 */

#endregion

using System;
using System.Data;
using System.Data.Common;

namespace Masterduner.SourceStudio.Practices.DevelopmentLibrary.Data.Common
{
    /// <summary>
    /// <para>Masterduner.SourceStudio.Practices.DevelopmentLibrary.Data.Common.Database</para>
    /// <para>
    /// 定义数据库操作的基本方法。
    /// </para>
    /// </summary>
    /// <remarks>
    /// <para>Target Framework Version : 4.0</para>
    /// </remarks>
    public abstract class Database : IDisposable
    {
        private string _connectionString;
        private DatabaseExceptionProcessMode _exceptionHandling;
        private int _executeTimeout;
        private DbConnection _dbConnection;
        #region DefaultDataSetName
        /// <summary>
        /// 默认数据集名称。
        /// </summary>
        public const string DefaultDataSetName = "System.Data.DataSet";
        #endregion

        #region ConnectionString
        /// <summary>
        /// 获取数据库连接串。
        /// </summary>
        public virtual string ConnectionString
        {
            get { return _connectionString; }
            protected set { _connectionString = value; }
        }
        #endregion

        #region ExceptionHandling
        /// <summary>
        /// 设置或获取数据库异常处理方式。
        /// </summary>
        public virtual DatabaseExceptionProcessMode ExceptionHandling
        {
            get { return _exceptionHandling; }
            set { _exceptionHandling = value; }
        }
        #endregion

        #region ExecuteTimeout
        /// <summary>
        /// 设置或获取数据库命令执行超时秒数。
        /// </summary>
        public virtual int ExecuteTimeout
        {
            get { return _executeTimeout; }
            set { _executeTimeout = value; }
        }
        #endregion

        #region Constructor

        /// <summary>
        /// <para>构造函数：</para>
        /// <para>初始化一个<see cref="Database" />对象实例。</para>
        /// </summary>
        protected Database(string connectionString)
        {
            this.ConnectionString = connectionString;
            this.ExceptionHandling = DatabaseExceptionProcessMode.Default;
            this.ExecuteTimeout = 0;
        }

        #endregion

        /// <summary>
        /// 数据库事件。
        /// </summary>
        public event DatabaseEventHandler DatabaseEvent;

        #region RaiseDatabaseEvent
        /// <summary>
        /// 引发DatabaseEvent事件。
        /// </summary>
        /// <param name="e"><see cref="DatabaseEventArgs"/>对象实例。</param>
        protected virtual void RaiseDatabaseEvent(DatabaseEventArgs e)
        {
            if (this.DatabaseEvent.NotIsNull()) this.DatabaseEvent(this, e);
        }
        #endregion

        #region ThrowAndRaise
        /// <summary>
        /// 用于抛出异常，并引发数据库事件。
        /// </summary>
        /// <param name="exception"><see cref="DatabaseExceptionWrapper"/>对象实例。</param>
        protected virtual void ThrowAndRaise(DatabaseExceptionWrapper exception)
        {
            if (this.ExceptionHandling.Equals(DatabaseExceptionProcessMode.Default) || this.ExceptionHandling.Equals(DatabaseExceptionProcessMode.CatchAndThrow))
                throw exception;
            if (this.ExceptionHandling.Equals(DatabaseExceptionProcessMode.Default) || this.ExceptionHandling.Equals(DatabaseExceptionProcessMode.OnlyCatch))
                this.RaiseDatabaseEvent(new DatabaseEventArgs(false, null, typeof(DatabaseExceptionWrapper), exception));
        }
        #endregion

        #region DbConnection
        /// <summary>
        /// 设置或获取数据库连接对象实例。
        /// </summary>
        protected virtual DbConnection DbConnection
        {
            get { return _dbConnection; }
            set { _dbConnection = value; }
        }
        #endregion

        #region InitialDbConnection
        /// <summary>
        /// 初始化数据库连接对象实例。
        /// </summary>
        protected abstract void InitialDbConnection();
        #endregion

        #region Open
        /// <summary>
        /// 打开数据库连接。
        /// </summary>
        public virtual void Open()
        {
            if (this.DbConnection.IsNull()) this.InitialDbConnection();
            try
            {
                this.DbConnection.Open();
            }
            catch (Exception ex)
            {
                this.ThrowAndRaise(new DatabaseExceptionWrapper(ex));
            }
        }
        #endregion

        #region Close
        /// <summary>
        /// 关闭数据库连接。
        /// </summary>
        public virtual void Close()
        {
            if (this.DbConnection.NotIsNull())
            {
                try
                {
                    this.DbConnection.Close();
                }
                catch (Exception ex)
                {
                    this.ThrowAndRaise(new DatabaseExceptionWrapper(ex));
                }
            }
        }
        #endregion

        #region BeginDbTransaction
        /// <summary>
        /// 启用一个数据库事务。
        /// </summary>
        /// <returns><see cref="DbTransaction"/>对象实例。</returns>
        public virtual DbTransaction BeginDbTransaction()
        {
            try
            {
                return this.DbConnection.BeginTransaction();
            }
            catch (Exception ex)
            {
                this.ThrowAndRaise(new DatabaseExceptionWrapper(ex));
            }
            return null;
        }

        /// <summary>
        /// 启用一个数据库事务。
        /// </summary>
        /// <param name="iso"><see cref="IsolationLevel"/>中的一个值。</param>
        /// <returns><see cref="DbTransaction"/>对象实例。</returns>
        public virtual DbTransaction BeginDbTransaction(IsolationLevel iso)
        {
            try
            {
                this.BeginDbTransaction(iso);
            }
            catch (Exception ex)
            {
                this.ThrowAndRaise(new DatabaseExceptionWrapper(ex));
            }
            return null;
        }
        #endregion

        #region Commit
        /// <summary>
        /// 提交一个数据库事务。
        /// </summary>
        /// <param name="transaction"><see cref="DbTransaction"/>对象实例。</param>
        public virtual void Commit(DbTransaction transaction)
        {
            try
            {
                transaction.Commit();
            }
            catch (Exception ex)
            {
                this.ThrowAndRaise(new DatabaseExceptionWrapper(ex));
            }
        }
        #endregion

        #region Rollback
        /// <summary>
        /// 回滚一个数据库事务。
        /// </summary>
        /// <param name="transaction"><see cref="DbTransaction"/>对象实例。</param>
        public virtual void Rollback(DbTransaction transaction)
        {
            try
            {
                transaction.Rollback();
            }
            catch (Exception ex)
            {
                this.ThrowAndRaise(new DatabaseExceptionWrapper(ex));
            }
        }
        #endregion

        #region CreateDbCommand
        /// <summary>
        /// 创建一个数据库命令对象实例。
        /// </summary>
        /// <param name="cmdText">数据库命令文本。</param>
        /// <param name="cmdType"><see cref="CommandType"/>中的一个值。</param>
        /// <returns><see cref="DbCommand"/>对象实例。</returns>
        public abstract DbCommand CreateDbCommand(string cmdText, CommandType cmdType = CommandType.Text);

        /// <summary>
        /// 创建一个事务性的数据库命令对象实例。
        /// </summary>
        /// <param name="cmdText">数据库命令文本。</param>
        /// <param name="transaction"><see cref="DbTransaction"/>对象实例。</param>
        /// <param name="cmdType"><see cref="CommandType"/>中的一个值。</param>
        /// <returns><see cref="DbCommand"/>对象实例。</returns>
        public abstract DbCommand CreateDbCommand(string cmdText, DbTransaction transaction, CommandType cmdType = CommandType.Text);
        #endregion

        #region CreateParameterName
        /// <summary>
        /// 创建完整的数据库参数名称。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <returns>完整的数据库参数名称。</returns>
        protected virtual string CreateParameterName(string name)
        {
            return name.StartsWith("@") ? name : string.Format(@"@{0}", name);
        }
        #endregion

        #region CreateDbParameter
        /// <summary>
        /// 创建一个数据库命令参数对象实例。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <param name="value">参数值。</param>
        /// <param name="direction"><see cref="ParameterDirection"/>中的一个值。</param>
        /// <param name="dbType"><see cref="DbType"/>中的一个值。</param>
        /// <returns><see cref="DbParameter"/>对象实例。</returns>
        public abstract DbParameter CreateDbParameter(string name, object value, ParameterDirection direction = ParameterDirection.Input, DbType dbType = DbType.AnsiString);
        #endregion

        #region AddParameter
        /// <summary>
        /// 添加<paramref name="parameter"/>到<paramref name="cmd"/>中。
        /// </summary>
        /// <param name="cmd">数据库命令对象实例。</param>
        /// <param name="parameter">数据库命令参数对象实例。</param>
        public virtual void AddParameter(DbCommand cmd, DbParameter parameter)
        {
            cmd.Parameters.Add(parameter);
        }
        #endregion

        #region AddParameters
        /// <summary>
        /// 添加<paramref name="parameters"/>到<paramref name="cmd"/>中。
        /// </summary>
        /// <param name="cmd">数据库命令对象实例。</param>
        /// <param name="parameters"><see cref="DbParameter"/>[]。</param>
        public virtual void AddParameters(DbCommand cmd, params DbParameter[] parameters)
        {
            if (parameters.NotIsNull() && parameters.Length > 0)
            {
                foreach (DbParameter item in parameters) this.AddParameter(cmd, item);
            }
        }
        #endregion

        #region Fill
        /// <summary>
        /// 执行数据库命令并填充<paramref name="dataSet"/>。
        /// </summary>
        /// <param name="selectCmd">数据库查询命令对象实例。</param>
        /// <param name="dataSet">需要填充的<see cref="DataSet"/>对象实例。</param>
        /// <param name="dataSetName">数据集名称。</param>
        public abstract void Fill(DbCommand selectCmd, DataSet dataSet, string dataSetName = Database.DefaultDataSetName);

        /// <summary>
        /// 执行数据库命令并填充<paramref name="dataSet"/>。
        /// </summary>
        /// <param name="selectCmdText">数据库查询命令文本。</param>
        /// <param name="dataSet">需要填充的<see cref="DataSet"/>对象实例。</param>
        /// <param name="dataSetName">数据集名称。</param>
        public virtual void Fill(string selectCmdText, DataSet dataSet, string dataSetName = Database.DefaultDataSetName)
        {
            this.Fill(this.CreateDbCommand(selectCmdText), dataSet, dataSetName);
        }
        #endregion

        #region ExecuteDataSet
        /// <summary>
        /// 执行数据库查询命令并返回数据集。
        /// </summary>
        /// <param name="selectCmd">数据库查询命令对象实例。</param>
        /// <param name="dataSetName">数据集名称。</param>
        /// <returns><see cref="DataSet"/>对象实例。</returns>
        public virtual DataSet ExecuteDataSet(DbCommand selectCmd, string dataSetName = Database.DefaultDataSetName)
        {
            DataSet dataSet = new DataSet();
            this.Fill(selectCmd, dataSet, dataSetName);
            return dataSet;
        }

        /// <summary>
        /// 执行数据库查询命令并返回数据集。
        /// </summary>
        /// <param name="selectCmdText">数据库查询命令文本。</param>
        /// <param name="dataSetName">数据集名称。</param>
        /// <returns><see cref="DataSet"/>对象实例。</returns>
        public virtual DataSet ExecuteDataSet(string selectCmdText, string dataSetName = Database.DefaultDataSetName)
        {
            return this.ExecuteDataSet(this.CreateDbCommand(selectCmdText), dataSetName);
        }
        #endregion

        #region ExecuteReader
        /// <summary>
        /// 执行数据库命令，并返回<see cref="DbDataReader"/>对象实例。
        /// </summary>
        /// <param name="cmd"><see cref="DbCommand"/>对象实例。</param>
        /// <param name="behavior"><see cref="CommandBehavior"/>中的一个值。</param>
        /// <returns><see cref="DbDataReader"/>对象实例。</returns>
        public virtual DbDataReader ExecuteReader(DbCommand cmd, CommandBehavior behavior = CommandBehavior.Default)
        {
            try
            {
                DbDataReader dataReader = cmd.ExecuteReader(behavior);
                this.RaiseDatabaseEvent(new DatabaseEventArgs(true, dataReader, typeof(DbDataReader), null));
                return dataReader;
            }
            catch (Exception ex)
            {
                this.ThrowAndRaise(new DatabaseExceptionWrapper(cmd.CommandText, ex, cmd.CommandType.ToCmdTypeString()));
            }
            return null;
        }

        /// <summary>
        /// 执行数据库命令，并返回<see cref="DbDataReader"/>对象实例。
        /// </summary>
        /// <param name="cmdText">数据库命令文本。</param>
        /// <param name="behavior"><see cref="CommandBehavior"/>中的一个值。</param>
        /// <returns><see cref="DbDataReader"/>对象实例。</returns>
        public virtual DbDataReader ExecuteReader(string cmdText, CommandBehavior behavior = CommandBehavior.Default)
        {
            return this.ExecuteReader(this.CreateDbCommand(cmdText));
        }

        /// <summary>
        /// 执行数据库命令，并调用<paramref name="handler"/>对结果集进行操作。
        /// </summary>
        /// <typeparam name="TReader">派生自<see cref="DbDataReader"/>的对象实例。</typeparam>
        /// <param name="cmd">数据库命令对象实例。</param>
        /// <param name="handler"><see cref="DatabaseReaderHandler{T}"/>方法委托。</param>
        /// <param name="behavior"><see cref="CommandBehavior"/>中的一个值。</param>
        /// <remarks>
        /// 此方法不会出发DatabaseEvent事件。
        /// </remarks>
        public virtual void ExecuteReader<TReader>(DbCommand cmd, DatabaseReaderHandler<TReader> handler, CommandBehavior behavior = CommandBehavior.Default)
            where TReader : DbDataReader
        {
            try
            {
                DbDataReader dataReader = cmd.ExecuteReader(behavior);
                int dataSetIndex = 0;
                int rowIndex = 0;
                do
                {
                    rowIndex = 0;
                    while (dataReader.Read())
                    {
                        handler(dataReader.ForceTo<TReader>(), rowIndex, dataSetIndex);
                        rowIndex++;
                    }
                    dataSetIndex++;
                }
                while (dataReader.NextResult());
            }
            catch (Exception ex)
            {
                this.ThrowAndRaise(new DatabaseExceptionWrapper(cmd.CommandText, ex, cmd.CommandType.ToCmdTypeString()));
            }
        }

        /// <summary>
        /// 执行数据库命令，并调用<paramref name="handler"/>对结果集进行操作。
        /// </summary>
        /// <typeparam name="TReader">派生自<see cref="DbDataReader"/>的对象实例。</typeparam>
        /// <param name="cmdText">数据库命令文本。</param>
        /// <param name="handler"><see cref="DatabaseReaderHandler{T}"/>方法委托。</param>
        /// <param name="behavior"><see cref="CommandBehavior"/>中的一个值。</param>
        /// <remarks>
        /// 此方法不会出发DatabaseEvent事件。
        /// </remarks>
        public virtual void ExecuteReader<TReader>(string cmdText, DatabaseReaderHandler<TReader> handler, CommandBehavior behavior = CommandBehavior.Default)
            where TReader : DbDataReader
        {
            this.ExecuteReader<TReader>(this.CreateDbCommand(cmdText), handler, behavior);
        }
        #endregion

        #region ExecuteNonQuery
        /// <summary>
        /// 执行数据库命令并返回影响行数。
        /// </summary>
        /// <param name="cmd">数据库命令对象实例。</param>
        /// <returns>影响行数。</returns>
        public virtual int ExecuteNonQuery(DbCommand cmd)
        {
            try
            {
                int effectRowCount = cmd.ExecuteNonQuery();
                this.RaiseDatabaseEvent(new DatabaseEventArgs(true, effectRowCount, typeof(int), null));
                return effectRowCount;
            }
            catch (Exception ex)
            {
                this.ThrowAndRaise(new DatabaseExceptionWrapper(cmd.CommandText, ex, cmd.CommandType.ToCmdTypeString()));
            }
            return -1;
        }

        /// <summary>
        /// 执行数据库命令并返回影响行数。
        /// </summary>
        /// <param name="cmdText">数据库命令文本。</param>
        /// <returns>影响行数。</returns>
        public virtual int ExecuteNonQuery(string cmdText)
        {
            return this.ExecuteNonQuery(this.CreateDbCommand(cmdText));
        }
        #endregion

        #region ExecuteScalar
        /// <summary>
        /// 执行数据库命令并返回标量值。
        /// </summary>
        /// <param name="cmd">数据库命令对象实例。</param>
        /// <returns><see cref="Object"/>对象实例。</returns>
        public virtual object ExecuteScalar(DbCommand cmd)
        {
            try
            {
                object scalar = cmd.ExecuteScalar();
                this.RaiseDatabaseEvent(new DatabaseEventArgs(true, scalar, scalar.IsNull() ? typeof(object) : scalar.GetType(), null));
                return scalar;
            }
            catch (Exception ex)
            {
                this.ThrowAndRaise(new DatabaseExceptionWrapper(cmd.CommandText, ex, cmd.CommandType.ToCmdTypeString()));
            }
            return null;
        }

        /// <summary>
        /// 执行数据库命令并返回标量值。
        /// </summary>
        /// <param name="cmdText">数据库命令文本。</param>
        /// <returns><see cref="Object"/>对象实例。</returns>
        public virtual object ExecuteScalar(string cmdText)
        {
            return this.ExecuteScalar(this.CreateDbCommand(cmdText));
        }
        #endregion

        #region Dispose
        /// <summary>
        /// 释放<see cref="Database"/>对象实例。
        /// </summary>
        public virtual void Dispose()
        {
            if (this.DbConnection.NotIsNull())
            {
                if (this.DbConnection.State.Equals(ConnectionState.Open))
                    this.DbConnection.Close();
                this.DbConnection.Dispose();
                this.DbConnection = null;
            }
        }
        #endregion
    }
}

#region README

/*
 * ####     ©2014 Wang Yucai
 * 
 * ####     Contact me
 *                  
 *                  E-mail : Masterduner@Yeah.net
 *                  Mobile : 13621384677
 *                  QQ : 180261899
 */

#endregion